﻿#region File Header
//-----------------------------------------------------------------------------
// SibLib
//
// Copyright (C) 2010 Julien Villers
// This program is distributed under the terms of the 
// GNU Lesser General Public License (LGPL).
// See Docs/lgpl.txt and Docs/gpl.txt
//-----------------------------------------------------------------------------
#endregion

using System;
using System.Text;

namespace SibLib.Text
{
    /// <summary>
    /// Provide helper methods to handle strings and string buffers.
    /// </summary>
    public static class StringTools
    {
        /// <summary>
        /// Note: this is used for conversions.
        /// </summary>
        private readonly static char [] m_CharBuffer = new char[32];

        /// <summary>
        /// Append an int value to a StringBuilder.
        /// </summary>
        /// <param name="stringBuild">An initialized StringBuilder, empty or not.</param>
        /// <param name="value">The int value to be converted to string.</param>
        public static void AppendIntToStringBuilder(StringBuilder stringBuild, int value)   // TODO: extension method, float with specified precision would come handy
        {
            int index = 0;
            if (value < 0)
            {
                stringBuild.Append('-');
                value = -value;
            }

            do
            {
                int modulus = value % 10;                           // Note: could also remove the modulus, replace by sub/mult.
                value /= 10;

                m_CharBuffer[index] = (char)('0' + modulus);        // Note: I'm not testing for overflows, buffer is huge compared to max int value.
                index++;
            }
            while (value > 0);

            for (int i = index - 1; i >= 0; i--)
                stringBuild.Append(m_CharBuffer[i]);
        }

        /// <summary>
        /// Append a time value to a StringBuilder.
        /// Format is:
        ///     h:mm:ss         if at least one hour.
        /// or
        ///     mm:ss           if at least ten minutes
        /// or
        ///     m:ss            if less than ten minutes (includes less than one minute).
        /// </summary>
        /// <param name="stringBuild">An initialized StringBuilder, empty or not.</param>
        /// <param name="seconds"></param>
        public static void TimeToStringBuilder(StringBuilder stringBuild, int seconds)
        {
            int minutes = seconds / 60;
            seconds -= (minutes * 60);
            if (minutes >= 60)
            {
                int hours = minutes / 60;
                minutes -= 60;
                AppendIntToStringBuilder(stringBuild, hours);
                stringBuild.Append(':');
                if (minutes < 10)
                    stringBuild.Append('0');
            }

            AppendIntToStringBuilder(stringBuild, minutes);
            stringBuild.Append(':');
            if (seconds < 10)
                stringBuild.Append('0');
            AppendIntToStringBuilder(stringBuild, seconds);
        }

        #region TimeSpan

        /// <summary>
        /// Append a duration to a StringBuilder.
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static void TimeToDisplayString(StringBuilder stringBuild, TimeSpan time)
        {
            // TODO: maximum? This will look ridiculous with too much days.
            int days = time.Days;
            int hours = time.Hours;
            if (days > 2)
            {
                AppendIntToStringBuilder(stringBuild, days);
                stringBuild.Append(" days");
                return;
            }

            if (days > 0)
            {
                AppendIntToStringBuilder(stringBuild, days);
                stringBuild.Append(" days and ");
                AppendIntToStringBuilder(stringBuild, hours);
                stringBuild.Append((hours > 1) ? " hours" : " hour");
                return;
            }

            if (hours > 5)
            {
                AppendIntToStringBuilder(stringBuild, hours);
                stringBuild.Append(" hours");
                return;
            }

            int minutes = time.Minutes;
            if (hours == 0)
            {
                if (minutes > 5)
                {
                    AppendIntToStringBuilder(stringBuild, minutes);
                    stringBuild.Append(" minutes");
                }
                else
                {
                    stringBuild.Append("moments ago");
                    return;
                }
            }

            if (minutes >= 5)
            {
                AppendIntToStringBuilder(stringBuild, hours);
                stringBuild.Append((hours > 1) ? " hours" : " hour");
                stringBuild.Append(" and ");
                AppendIntToStringBuilder(stringBuild, (minutes - (minutes % 5)));
                stringBuild.Append(" minutes");
                return;
            }

            AppendIntToStringBuilder(stringBuild, hours);
            stringBuild.Append((hours > 1) ? " hours" : " hour");
        }
        #endregion
    }
}
